﻿// ------------------------------------------------------------------------------
// <copyright file="TimePicker.cs" company="skumaronline.com">
//    Copyright (C) 2012 Suresh Kumar T.
//
//    This program is free software; you can redistribute it and/or
//    modify it under the terms of the GNU General Public License
//    as published by the Free Software Foundation version 2
//    of the License.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    http://www.gnu.org/licenses/gpl-2.0.html
//
// </copyright>
// ------------------------------------------------------------------------------

namespace StoreAppLib.Controls
{
    using System;
    using Windows.UI;
    using Windows.UI.Core;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Media;

    /// <summary>
    /// TimePicker control class
    /// </summary>
    public sealed class TimePicker : TextBox
    {
        /// <summary>
        /// Time property
        /// </summary>
        public static readonly DependencyProperty TimeProperty =
            DependencyProperty.Register("Time", typeof(DateTime), typeof(TimePicker), new PropertyMetadata(DateTime.MinValue, OnChangeTimeProperty));

        /// <summary>
        /// Format property
        /// </summary>
        public static readonly DependencyProperty FormatProperty =
            DependencyProperty.Register("Format", typeof(string), typeof(TimePicker), new PropertyMetadata("hh:mm:ss tt", OnChangeTimeProperty));

        /// <summary>
        /// Auto select property
        /// </summary>
        public static readonly DependencyProperty AutoSelectProperty =
            DependencyProperty.Register("AutoSelect", typeof(bool), typeof(TimePicker), new PropertyMetadata(false));

        /// <summary>
        /// Inner background property
        /// </summary>
        public static readonly DependencyProperty InnerBackgroundProperty =
            DependencyProperty.Register("InnerBackground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Transparent)));

        /// <summary>
        /// Inner border brush property
        /// </summary>
        public static readonly DependencyProperty InnerBorderBrushProperty =
            DependencyProperty.Register("InnerBorderBrush", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        /// <summary>
        /// Outer border brush property
        /// </summary>
        public static readonly DependencyProperty OuterBorderBrushProperty =
            DependencyProperty.Register("OuterBorderBrush", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        /// <summary>
        /// Outer background property
        /// </summary>
        public static readonly DependencyProperty OuterBackgroundProperty =
            DependencyProperty.Register("OuterBackground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.White)));

        /// <summary>
        /// Button foreground property
        /// </summary>
        public static readonly DependencyProperty ButtonForegroundProperty =
            DependencyProperty.Register("ButtonForeground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        /// <summary>
        /// Header foreground property
        /// </summary>
        public static readonly DependencyProperty HeaderForegroundProperty =
            DependencyProperty.Register("HeaderForeground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Gray)));

        /// <summary>
        /// Time property
        /// </summary>
        public static readonly DependencyProperty TimeForegroundProperty =
            DependencyProperty.Register("TimeForeground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.Black)));

        /// <summary>
        /// Surface background property
        /// </summary>
        public static readonly DependencyProperty SurfaceBackgroundProperty =
            DependencyProperty.Register("SurfaceBackground", typeof(Brush), typeof(TimePicker), new PropertyMetadata(new SolidColorBrush(Colors.White)));

        /// <summary>
        /// Initializes a new instance of the <see cref="TimePicker" /> class
        /// </summary>
        public TimePicker()
            : base()
        {
            base.IsReadOnly = true;
        }

        /// <summary>
        /// Gets or sets the time
        /// </summary>
        public DateTime Time
        {
            get { return (DateTime)this.GetValue(TimeProperty); }
            set { this.SetValue(TimeProperty, value); }
        }

        /// <summary>
        /// Gets or sets the time format
        /// </summary>
        public string Format
        {
            get { return (string)this.GetValue(FormatProperty); }
            set { this.SetValue(FormatProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether to update date when time is scrolling
        /// </summary>
        public bool AutoSelect
        {
            get { return (bool)this.GetValue(AutoSelectProperty); }
            set { this.SetValue(AutoSelectProperty, value); }
        }

        /// <summary>
        /// Gets or sets inner background
        /// </summary>
        public Brush InnerBackground
        {
            get { return (Brush)this.GetValue(InnerBackgroundProperty); }
            set { this.SetValue(InnerBackgroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets inner border brush
        /// </summary>
        public Brush InnerBorderBrush
        {
            get { return (Brush)this.GetValue(InnerBorderBrushProperty); }
            set { this.SetValue(InnerBorderBrushProperty, value); }
        }

        /// <summary>
        /// Gets or sets outer border brush
        /// </summary>
        public Brush OuterBorderBrush
        {
            get { return (Brush)this.GetValue(OuterBorderBrushProperty); }
            set { this.SetValue(OuterBorderBrushProperty, value); }
        }

        /// <summary>
        /// Gets or sets outer background
        /// </summary>
        public Brush OuterBackground
        {
            get { return (Brush)this.GetValue(OuterBackgroundProperty); }
            set { this.SetValue(OuterBackgroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets button foreground
        /// </summary>
        public Brush ButtonForeground
        {
            get { return (Brush)this.GetValue(ButtonForegroundProperty); }
            set { this.SetValue(ButtonForegroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets header foreground
        /// </summary>
        public Brush HeaderForeground
        {
            get { return (Brush)this.GetValue(HeaderForegroundProperty); }
            set { this.SetValue(HeaderForegroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets time foreground
        /// </summary>
        public Brush TimeForeground
        {
            get { return (Brush)this.GetValue(TimeForegroundProperty); }
            set { this.SetValue(TimeForegroundProperty, value); }
        }

        /// <summary>
        /// Gets or sets the control surface background
        /// </summary>
        public Brush SurfaceBackground
        {
            get { return (Brush)this.GetValue(SurfaceBackgroundProperty); }
            set { this.SetValue(SurfaceBackgroundProperty, value); }
        }

        /// <summary>
        /// Gets a value indicating whether control is readonly. Shadow base property to show always in readonly mode
        /// </summary>
        private new bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// Gets a text value. Shadow base property to hide text, instead use Value property
        /// </summary>
        private new string Text
        {
            get { return string.Empty; }
        }

        /// <summary>
        /// When user tap on the time picker, show the time control in a popup
        /// </summary>
        /// <param name="e">Routed event argument</param>
        protected override void OnTapped(Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
        {
            e.Handled = true;
            base.OnTapped(e);
            
            TimeControl timeControl = new TimeControl(this.Time);

            timeControl.AutoSelect = this.AutoSelect;
            timeControl.InnerBackground = this.InnerBackground;
            timeControl.InnerBorderBrush = this.InnerBorderBrush;
            timeControl.HeaderForeground = this.HeaderForeground;
            timeControl.Background = this.OuterBackground;
            timeControl.BorderBrush = this.OuterBorderBrush;
            timeControl.Foreground = this.TimeForeground;
            timeControl.ButtonForeground = this.ButtonForeground;
            timeControl.SurfaceBackground = this.SurfaceBackground;

            timeControl.TwentyFourHour = this.Format.Contains("H");

            timeControl.TimeChanged += this.OnTimeChanged;

            PopupManager.Open(this, timeControl, PopupAlignment.Center);
        }

        /// <summary>
        /// When time property changes update the text value
        /// </summary>
        /// <param name="source">The source</param>
        /// <param name="args">The argument</param>
        private static void OnChangeTimeProperty(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            TimePicker timePicker = source as TimePicker;

            timePicker.UpdateText();
        }

        /// <summary>
        /// Fires when time changes
        /// </summary>
        /// <param name="sender">The source</param>
        /// <param name="args">Date time change argument</param>
        private async void OnTimeChanged(object sender, DateTimeEventArgs args)
        {
            if (this.Time != args.DateTime || string.IsNullOrEmpty(base.Text))
            {
                await this.Dispatcher.RunAsync(
                    CoreDispatcherPriority.Normal,
                    () =>
                    {
                        this.Time = args.DateTime;
                    });
            }
        }

        /// <summary>
        /// Set the time to this control to display
        /// </summary>
        private void UpdateText()
        {
            if (!string.IsNullOrWhiteSpace(this.Format))
            {
                base.Text = this.Time.ToString(this.Format);
            }
            else
            {
                base.Text = string.Empty;
            }
        }
    }
}
